package com.yao.aspect;

import com.alibaba.fastjson2.JSONObject;
import com.yao.bean.R;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Component;
import org.springframework.web.util.HtmlUtils;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

/**
 * Copyright (C), 2022-2022, 姚兵
 * Author: 32210
 * Date: 2022/11/3 14:07
 * FileName: OauthTokenAspect
 * Description:
 */

@Component
@Aspect
@Slf4j
public class OauthTokenAspect {

    private WebResponseExceptionTranslator<OAuth2Exception> exceptionTranslator = new DefaultWebResponseExceptionTranslator();

    @Pointcut("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public void oauthToken(){

    }


    @Pointcut("execution(* org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(..))")
    public void checkToken(){

    }


    @Around(value = "oauthToken()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Exception {
        System.out.println("before");
        try {
            ResponseEntity<OAuth2AccessToken> result = (ResponseEntity<OAuth2AccessToken>) proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
            return ResponseEntity.ok().body(R.ok().data(result.getBody())) ;
        } catch (Throwable t) {
            t.printStackTrace();
            log.info("oauthToken Handling error: " + t.getClass().getSimpleName() + ", " + t.getMessage());
            // This isn't an oauth resource, so we don't want to send an
            // unauthorized code here. The client has already authenticated
            // successfully with basic auth and should just
            // get back the invalid token error.
            @SuppressWarnings("serial")
            InvalidTokenException e400 = new InvalidTokenException(t.getMessage()) {
                @Override
                public int getHttpErrorCode() {
                    return 400;
                }
            };

            ResponseEntity<OAuth2Exception> translate = exceptionTranslator.translate(e400);


            log.info("oauthToken Handling translate={}",translate.getBody());
            OAuth2Exception body = translate.getBody();
            Map<Object, Object> map = new HashMap<>();
            map.put("error",body.getOAuth2ErrorCode());

            String errorMessage = body.getMessage();
            if (errorMessage != null) {
                errorMessage = HtmlUtils.htmlEscape(errorMessage);
            }
            map.put("error_description",body.getMessage());

            if (body.getAdditionalInformation()!=null) {
                for (Map.Entry<String, String> entry : body.getAdditionalInformation().entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    map.put(key,value);
                }
            }
            return ResponseEntity.badRequest().body(R.err().data(map));
        }
    }

    @Around(value = "checkToken()")
    public Object aroundAdviceCheckToken(ProceedingJoinPoint proceedingJoinPoint) throws Exception {
        System.out.println("before");
        try {
            Map<String,?> result = (Map<String,?>) proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());

            return JSONObject.parseObject(JSONObject.toJSONString(R.ok().data(result)),Map.class);
        } catch (Throwable t) {
            t.printStackTrace();
            log.info("Handling error: " + t.getClass().getSimpleName() + ", " + t.getMessage());
            // This isn't an oauth resource, so we don't want to send an
            // unauthorized code here. The client has already authenticated
            // successfully with basic auth and should just
            // get back the invalid token error.
            @SuppressWarnings("serial")
            InvalidTokenException e400 = new InvalidTokenException(t.getMessage()) {
                @Override
                public int getHttpErrorCode() {
                    return 400;
                }
            };

            ResponseEntity<OAuth2Exception> translate = exceptionTranslator.translate(e400);


            log.info("Handling translate={}",translate.getBody());
            OAuth2Exception body = translate.getBody();
            Map<Object, Object> map = new HashMap<>();
            map.put("error",body.getOAuth2ErrorCode());

            String errorMessage = body.getMessage();
            if (errorMessage != null) {
                errorMessage = HtmlUtils.htmlEscape(errorMessage);
            }
            map.put("error_description",body.getMessage());

            if (body.getAdditionalInformation()!=null) {
                for (Map.Entry<String, String> entry : body.getAdditionalInformation().entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    map.put(key,value);
                }
            }
            return JSONObject.parseObject(JSONObject.toJSONString(R.err().data(map)),Map.class);
        }finally {
            System.out.println("after");
        }

    }
}
